package com.hub.realtime.flinkshims.core;

import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


public class SqlSplitter {

    private static Set<String> singleLineCommentPrefixList = new HashSet<>();

    static {
        singleLineCommentPrefixList.add("--");
    }

    public static List<String> splitSql(String sql) {
        List<String> queries = new ArrayList<>();
        int lastIdx = StringUtils.isNotEmpty(sql) ? sql.length() - 1 : 0;
        StringBuilder query = new StringBuilder();

        boolean multiLineComment = false;
        boolean singleLineComment = false;
        boolean singleQuoteString = false;
        boolean doubleQuoteString = false;

        for (int idx = 0; idx < sql.length(); idx++) {
            char ch = sql.charAt(idx);
            if (singleLineComment && (ch == '\n')) {
                singleLineComment = false;
                query.append(ch);
                if (idx == lastIdx && StringUtils.isNotEmpty(query.toString().trim())) {
                    queries.add(query.toString());
                }
                break;
            }

            if (multiLineComment && (idx - 1) > 0 && sql.charAt(idx - 1) == '/' && (idx - 2) >= 0 && sql.charAt(idx - 2) == '*') {
                multiLineComment = false;
            }


            if (ch == '\'' && !(singleLineComment || multiLineComment)) {
                if (singleQuoteString) {
                    singleQuoteString = false;
                } else if (!doubleQuoteString) {
                    singleQuoteString = true;
                }
            }

            if (ch == '"' && !(singleLineComment || multiLineComment)) {
                if (doubleQuoteString && idx > 0) {
                    doubleQuoteString = false;
                } else if (!singleQuoteString) {
                    doubleQuoteString = true;
                }
            }


            if (!singleQuoteString && !doubleQuoteString && !multiLineComment && !singleLineComment && idx < lastIdx) {
                if (isSingleLineComment(sql.charAt(idx), sql.charAt(idx + 1))) {
                    singleLineComment = true;
                } else if (sql.charAt(idx) == '/' && sql.length() > (idx + 2)
                        && sql.charAt(idx + 1) == '*' && sql.charAt(idx + 2) != '+') {
                    multiLineComment = true;
                }
            }


            if (ch == ';' && !singleQuoteString && !doubleQuoteString && !multiLineComment && !singleLineComment) {
                if (StringUtils.isNotEmpty(query.toString().trim())) {
                    queries.add(query.toString());
                    query = new StringBuilder();
                }
            } else if (idx == lastIdx) {
                if (!singleLineComment && !multiLineComment) {
                    query.append(ch);
                }

                if (StringUtils.isNotEmpty(query.toString().trim())) {
                    queries.add(query.toString());
                    query = new StringBuilder();
                }
            } else if (!singleLineComment && !multiLineComment) {
                query.append(ch);
            } else if (ch == '\n') {
                query.append(ch);
            }


        }

        List<String> refinedQueries = new ArrayList<>();

        for (int i = 0; i < queries.size(); i++) {
            String currStatement = queries.get(i);
            if (isSingleLineComment(currStatement) || isMultipleLineComment(currStatement)) {
                if (!refinedQueries.isEmpty()) {
                    String lastRefinedQuery = refinedQueries.get(refinedQueries.size() - 1);
                    refinedQueries.set(refinedQueries.size() - 1, lastRefinedQuery + extractLineBreaks(currStatement));
                }
            } else {
                String linesPlaceholder = "";
                if (i > 0) {
                    linesPlaceholder = extractLineBreaks(refinedQueries.get(i - 1));
                }
                String refinedQuery = linesPlaceholder + currStatement;
                refinedQueries.add(refinedQuery);
            }


        }

        return refinedQueries;
    }


    private static boolean isSingleLineComment(char curChar, char nextChar) {
        for (String singleCommentPrefix : singleLineCommentPrefixList) {
            if (singleCommentPrefix.length() == 1) {
                if (curChar == singleCommentPrefix.charAt(0)) {
                    return true;
                }
            }
            if (singleCommentPrefix.length() == 2) {
                if (curChar == singleCommentPrefix.charAt(0) && nextChar == singleCommentPrefix.charAt(1)) {
                    return true;
                }
            }
        }
        return false;
    }


    private static boolean isSingleLineComment(String text) {
        return text.trim().startsWith("--");
    }

    private static boolean isMultipleLineComment(String text) {

        return text.trim().startsWith("/*") && text.trim().endsWith("*/");
    }

//    private static String extractLineBreaks(String text) {
//        StringBuilder builder = new StringBuilder();
//        boolean lastValueN = false;
//        for (int i = 0; i < text.length(); i++) {
//            if (text.charAt(i) == '\n') {
//                if (!lastValueN) {
//                    builder.append('\n');
//                }
//            } else {
//                lastValueN = true;
//            }
//        }
//        return builder.toString();
//    }


    private static String extractLineBreaks(String text) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < text.length(); i++) {
            if (text.charAt(i) == '\n') {
                    builder.append('\n');
            }
        }
        return builder.toString();
    }

}
